﻿#pragma once

#ifdef WIN32

#include "Platform/SystemEvent.h"
#include "Widgets/Mouse/MouseCursorType.h"
#include <queue>
#include <windows.h>

class CWindowsWindow;
class CTextInputInterface;

//windows 系统的消息循环以及窗口线程
//windows 的窗口和消息循环必须放在同一线程，否则会出现阻塞
//而且消息循环不能与主线程共用，否则会导致输入法变慢
//所以使用一个专门的线程来处理窗口和消息循环
//这个类所有的public函数都可以在主线程调用
class CWindowsOSThread
{
public:
    CWindowsOSThread();
    ~CWindowsOSThread();

    static CWindowsOSThread* Get();

    //阻塞当前线程直到窗口创建完成
    CWindowsWindow* CreateWindowWithBlock();

    //阻塞当前线程直到窗口Long值设置完成
    void SetWindowLongWithBlock(uint64_t WindowID, int Index, LONG NewLong);

    //阻塞当前线程直到窗口销毁
    void DestroyWindowWithBlock(CWindowsWindow* InWindowToDestroy);

    //获取单个收到的消息，阻塞当前线程,如果没有消息则返回空
    TOptional<SystemEvent> PopEvent();

    static CWindowsWindow* GetWindowFromID(uint64_t WindowID);
    static WPARAM ToWindowsKey(EKey InKey);

    void StartTextInput(uint64_t WindowID, SIntPoint IMEWidgetPosition);
    void StopTextInput();
    bool IsTextInputStarted() const;

    void UseSystemCursor(EMouseCursorType CursorType);
protected:
    void CreateAndRegisterWindowClass();
    
    static SIntPoint LastScreenMousePosition;

    //消息循环,如果有消息则返回true,否则返回false
    void MessageLoop();
    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static bool bWaitingNextChar;

    std::thread* Thread;
    std::atomic<bool> bIsRunning = false;

    //消息队列锁
    std::mutex EventQueueMutex;
    std::queue<SystemEvent> EventQueue;

    //创建的窗口
    std::atomic<bool> bIsWaitingCreateWindow = false;
    CWindowsWindow* CreatedWindow = nullptr;

    //设置窗口Long值
    std::atomic<bool> bIsWaitingSetWindowLong = false;
    uint64_t SetWindowLongWindowID = 0;
    int SetWindowLongIndex = 0;
    LONG SetWindowLongNewLong = 0;

    //等待销毁的窗口
    std::atomic<CWindowsWindow*> WaitingDestroyWindow = nullptr;

    CWindowsWindow* InnerCreateWindow();
    void InnerDestroyWindow(CWindowsWindow* InWindow);

    CTextInputInterface * TextInputInterface = nullptr;
    struct STextInputStartData
    {
        uint64_t WindowID;
        SIntPoint IMEWidgetPosition;
    };
    std::atomic<STextInputStartData> TextInputStartData;
    void InnerStartTextInput(uint64_t WindowID, SIntPoint IMEWidgetPosition);

    std::atomic<bool> bWaitingStopTextInput = false;
    void InnerStopTextInput();


    std::atomic<EMouseCursorType> DesiredCursorType = EMouseCursorType::Arrow;
    EMouseCursorType CurrentCursorType = EMouseCursorType::Undefined;
    void InnerUseSystemCursor(EMouseCursorType CursorType);
public:
    //the window that user is drag file over
    uint64_t DragFileOverWindow=0;
    TVector<SPath> DragingFiles;
    void OnDragFileEnter(uint64_t Window, const  TVector<SPath>&InFiles );
    void OnDragFileLeave();
    void OnDragFileOver();
    void OnFiledDroped();


    void CaptureMouse(uint64_t WindowID);
    void ReleaseMouseCapture();
protected:

    std::atomic<uint64_t> WantedMouseCaptureWindowID=0;
    uint64_t MouseCapturedWindowID=0;


};
#endif